home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / ms-0_06.lha / xms-0.06 / Ms.c < prev    next >
C/C++ Source or Header  |  1991-11-10  |  27KB  |  897 lines

  1. /* Ms.c - MandelSpawn popup widget */
  2.  
  3. /*  This file is part of MandelSpawn, a parallel Mandelbrot program for
  4.     the X window system.
  5.  
  6.     Copyright (C) 1990, 1991 Andreas Gustafsson
  7.  
  8.     MandelSpawn is free software; you can redistribute it and/or modify
  9.     it under the terms of the GNU General Public License, version 1,
  10.     as published by the Free Software Foundation.
  11.  
  12.     MandelSpawn is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License,
  18.     version 1, along with this program; if not, write to the Free 
  19.     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. /* This widget creates a window showing a part of the Mandelbrot set */
  23.  
  24. #include <stdio.h>
  25. #include <math.h>
  26.  
  27. #include <X11/IntrinsicP.h>
  28. #include <X11/Xos.h>
  29. #include <X11/StringDefs.h>
  30.  
  31. /* We need ntohs() and htonl(); on some systems (HP-UX comes to mind) */
  32. /* they are macros defined in <netinet/in.h> and nowhere else, with */
  33. /* no corresponding library function. */
  34. #include <netinet/in.h>    
  35.  
  36. #include "backward.h" /* X11R2 backward compatibility stuff */
  37.  
  38. #include "MsP.h" /* includes Ms.h which includes MsJob.h */
  39. #include "Mama.h"
  40.  
  41. extern XtAppContext thisApp;
  42. extern Display *myDisplay;
  43. extern Screen *myScreen;
  44.  
  45. /* Misc. functions */
  46. static void
  47.     ClassInitialize(), Initialize(), Resize(), Realize(), Destroy(), 
  48.     InvertBox(), EraseBox(), HideBox(), UnhideBox(),
  49.     DoExpose();
  50.  
  51. /* These are used by menu choises in R4menu.c */
  52. void ZoomIn(), WindowStats();
  53.  
  54. /* Action functions */
  55. static void
  56.     BeginBoxAction(), StretchBoxAction(), EndBoxAction(),
  57.     ZoomAction(), CloseAction(), QuitAction(), ApplStatsAction(), 
  58.     WindowStatsAction();
  59.  
  60. #ifdef MENU
  61. void MsCreateMenu();
  62. #endif
  63. #ifdef LABEL
  64. void MsCreateUnderflowLabel();
  65. #endif
  66.  
  67. static Boolean SetValues();
  68.  
  69.  
  70. /* supported visual type / iteration count length combinations */
  71. /* are obtained by ORing togeter one ITER_x and one DISP_x value */
  72.  
  73. #define ITER_BYTE        0
  74. #define ITER_WORD        1
  75.  
  76. #define DISP_unknown        0
  77. #define DISP_1plane32msb     2  /* like a Sun monochrome display */
  78. #define DISP_1plane32lsb     4  /* like a DECstation monochrome display */
  79. #define DISP_8plane        6  /* typical 8-plane framebuffer */
  80. #define DISP_generic        8  /* none of the above */
  81.  
  82.  
  83. /* Defaults */
  84.  
  85. static Dimension default_width = 400;    /* window width in pixels */
  86. static Dimension default_height = 250;    /* window height in pixels */
  87. static int default_iteration_limit = 0;    /* 0 means undefined */
  88. static double default_center_x = (-0.5); /* x coordinate of window center */
  89. static double default_center_y = 0.0;    /* y coordinate of window center */
  90. static double default_range = 4.0;     /* window range in x direction */
  91. static Bool default_center_box = True;    /* do we center the rubberband box? */
  92. static Bool default_julia = False;    /* do we show the Julia set? */
  93. static double default_c_x = 0.0;     /* c parameter for Julia, real */
  94. static double default_c_y = 0.0;    /* c parameter for Julia, im */
  95. static double default_julia_range = 4.0; /* window range for Julia */
  96. static double default_julia_center_x = 0.0; /* window center x for Julia */
  97. static double default_julia_center_y = 0.0; /* window center y for Julia */
  98. static char default_cursor[] = "top_left_arrow"; 
  99. static unsigned default_chunk_width = 32;
  100. static unsigned default_chunk_height = 32;
  101. static Bool default_sony_bug_workaround = False;
  102. static Bool default_crosshair_size = 3;
  103. static Bool default_show_interior = False;
  104.  
  105.  
  106. extern char msDefaultTranslations[];
  107.  
  108. #ifndef MENU
  109. /* Some of these bindings are less than obvious.  Don't complain, */
  110. /* get X11R4 and Xaw so you can use the popup menu in R4menu.c. */
  111. char msDefaultTranslations[] = 
  112.     "<Btn1Down>:    BeginBox()        \n\
  113.      <Btn1Motion>:    StretchBox()        \n\
  114.      <Btn1Up>:        EndBox()        \n\
  115.      Shift<Btn2Down>:    Zoom(nopop,nojulia,in)    \n\
  116.      <Btn2Down>:    Zoom(popup,nojulia,in)    \n\
  117.      Shift<Btn3Down>:    Quit()            \n\
  118.      <Btn3Down>:    Close()            \n\
  119.      Shift<Key>z:    Zoom(nopop,nojulia,in)    \n\
  120.      <Key>z:        Zoom(popup,nojulia,in)    \n\
  121.      Shift<Key>o:    Zoom(nopop,nojulia,out)    \n\
  122.      <Key>o:        Zoom(popup,nojulia,out)    \n\
  123.      Shift<Key>j:    Zoom(nopop,julia,in)    \n\
  124.      <Key>j:        Zoom(popup,julia,in)    \n\
  125.      <Key>s:        ApplStats()        \n\
  126.      <Key>w:        WindowStats()        \n\
  127.      <Key>c:        Close()            \n\
  128.      <Key>q:        Quit()            \n\
  129.   ";
  130. #endif
  131.  
  132. static XtActionsRec actionsList[] =
  133. {
  134.     { "BeginBox",    BeginBoxAction        },
  135.     { "EndBox",        EndBoxAction        },
  136.     { "StretchBox",    StretchBoxAction    },
  137.     { "Zoom",        ZoomAction        },
  138.     { "WindowStats",    WindowStatsAction    },
  139.     { "ApplStats",    ApplStatsAction        },
  140.     { "Close",        CloseAction        },
  141.     { "Quit",        QuitAction        }
  142. };
  143.  
  144. static XtResource resources[] = 
  145. {   /* Core resources */
  146.     { XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  147.     XtOffset(Widget, core.width), XtRDimension,
  148.     (caddr_t) &default_width },
  149.     { XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  150.     XtOffset(Widget, core.height), XtRDimension,
  151.     (caddr_t) &default_height },
  152.     /* Noncore resources */
  153.     { XtNiteration_limit, XtCValue, XtRInt, sizeof(int),
  154.     XtOffset(MsWidget, ms.xi.job.iteration_limit), XtRInt,
  155.     (caddr_t) &default_iteration_limit },
  156.     { XtNCenterX, XtCValue, XtRDouble, sizeof(double),
  157.     XtOffset(MsWidget, ms.xi.center_x), XtRDouble,
  158.     (caddr_t) &default_center_x },
  159.     { XtNCenterY, XtCValue, XtRDouble, sizeof(double),
  160.     XtOffset(MsWidget, ms.xi.center_y), XtRDouble,
  161.     (caddr_t) &default_center_y },
  162.     { XtNRange, XtCValue, XtRDouble, sizeof(double),
  163.     XtOffset(MsWidget, ms.xi.xrange), XtRDouble,
  164.     (caddr_t) &default_range },
  165.     { XtNCenterBox, XtCValue, XtRBool, sizeof(Bool),
  166.     XtOffset(MsWidget, ms.center_box), XtRBool,
  167.     (caddr_t) &default_center_box },
  168.     { XtNCursor, XtCValue, XtRCursor, sizeof(Cursor),
  169.     XtOffset(MsWidget, ms.my_cursor), XtRString,
  170.     (caddr_t) default_cursor },
  171.     { XtNMama, XtCValue, XtRPointer, sizeof(MamaWidget),
  172.     XtOffset(MsWidget, ms.mama), XtRPointer,
  173.     (caddr_t) 0 } ,
  174.     { XtNJulia, XtCValue, XtRBool, sizeof(Bool),
  175.     XtOffset(MsWidget, ms.xi.julia), XtRBool,
  176.     (caddr_t) &default_julia },
  177.     { XtNCX, XtCValue, XtRDouble, sizeof(double),
  178.     XtOffset(MsWidget, ms.xi.c_x), XtRDouble,
  179.     (caddr_t) &default_c_x },
  180.     { XtNCY, XtCValue, XtRDouble, sizeof(double),
  181.     XtOffset(MsWidget, ms.xi.c_y), XtRDouble,
  182.     (caddr_t) &default_c_y },
  183.     { XtNChunkWidth, XtCValue, XtRInt, sizeof(unsigned int),
  184.     XtOffset(MsWidget, ms.xi.chunk_width), XtRInt,
  185.     (caddr_t) &default_chunk_width },
  186.     { XtNChunkHeight, XtCValue, XtRInt, sizeof(unsigned int),
  187.     XtOffset(MsWidget, ms.xi.chunk_height), XtRInt,
  188.     (caddr_t) &default_chunk_height },
  189.     { XtNSony, XtCValue, XtRBool, sizeof(Bool),
  190.         XtOffset(MsWidget, ms.sony_bug_workaround), XtRBool,
  191.         (caddr_t) &default_sony_bug_workaround },
  192.     { XtNCrosshairSize, XtCValue, XtRInt, sizeof(int),
  193.         XtOffset(MsWidget, ms.crosshair_size), XtRInt,
  194.         (caddr_t) &default_crosshair_size },
  195.     { XtNInterior, XtCValue, XtRBool, sizeof(Bool),
  196.         XtOffset(MsWidget, ms.xi.show_interior), XtRBool,
  197.         (caddr_t) &default_show_interior }
  198.  
  199. };
  200.  
  201. MsClassRec msClassRec = 
  202. {   /* core fields */
  203.     { 
  204.     /* superclass        */    (WidgetClass) &compositeClassRec,
  205.     /* class_name        */    "MandelSpawn",
  206.     /* widget_size        */    sizeof(MsRec),
  207.     /* class_initialize        */      NULL,
  208.     /* class_part_initialize    */    NULL,
  209.     /* class_inited        */    FALSE,
  210.     /* initialize        */    Initialize,
  211.     /* initialize_hook        */    NULL,
  212.     /* realize            */    Realize,
  213.     /* actions            */    actionsList,
  214.     /* num_actions        */    XtNumber(actionsList),
  215.     /* resources        */    resources,
  216.     /* resource_count        */    XtNumber(resources),
  217.     /* xrm_class        */    NULL,
  218.     /* compress_motion        */    TRUE,
  219.     /* compress_exposure    */    FALSE,
  220.     /* compress_enterleave    */    TRUE,
  221.     /* visible_interest        */    FALSE,
  222.     /* destroy            */    Destroy,
  223.     /* resize            */    Resize,
  224.     /* expose            */    DoExpose,
  225.     /* set_values        */    SetValues,
  226.     /* set_values_hook        */    NULL,
  227.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  228.     /* get_values_hook        */    NULL,
  229.     /* accept_focus        */    NULL,
  230.     /* version            */    XtVersion,
  231.     /* callback_private        */    NULL,
  232.     /* tm_table            */    msDefaultTranslations,
  233.     /* query_geometry        */    NULL
  234.     },
  235.     /* CompositeClassPart fields */
  236.     { XtInheritGeometryManager,
  237.       XtInheritChangeManaged,
  238.       XtInheritInsertChild,
  239.       XtInheritDeleteChild
  240.     },
  241.     /* msClassPart fields */
  242.     {
  243.     /* dummy            */    0
  244.     }
  245. };
  246.  
  247. WidgetClass msWidgetClass = (WidgetClass) &msClassRec;
  248.  
  249.  
  250. /* Initialize the widget */
  251.  
  252. static void
  253. Initialize(request, new)
  254.      MsWidget   request;
  255.      MsWidget   new;
  256. { XGCValues gcv;
  257.   int depth = DefaultDepthOfScreen(XtScreen(new));
  258.   /* set up a GC for the rubberband box */
  259.   gcv.function=GXxor;
  260.   
  261.   /* "gcv.foreground=~0l" messes up the black-and-white mode of the */
  262.   /* X11R2 server for the Sony NWS-1510 4-plane display quite badly; */
  263.   /* I'd call that a server bug.  The code below works but assumes */
  264.   /* 2's complement. */
  265.   if(depth==32)
  266.     gcv.foreground=0xffffffff; /* 1<<32 is undefined, says K&R */
  267.   else
  268.     gcv.foreground= (1 << depth) - 1;
  269.   new->ms.box_gc=XtGetGC(new, GCFunction|GCForeground, &gcv);
  270.   new->ms.box_exists=False;
  271.   new->ms.box_hidden=0;
  272.   new->ms.rectbuffer=(XImage *) NULL; /* no rectangle buffer so far */
  273. #ifdef LABEL
  274.   new->ms.underflow=0;
  275.   new->ms.underflow_label=NULL;
  276. #endif
  277.   ms_init(&new->ms.xi, MamaWorkforce(new->ms.mama));
  278. }
  279.  
  280.  
  281. /* Initialize, or re-initialize widget fields that may need to be */
  282. /* changed when the widget is resized, zoomed or otherwise modified */
  283.  
  284. static void MsPrecalculate(w) MsWidget w;
  285. { int underflow;
  286.   w->ms.xi.height = w->core.height;
  287.   w->ms.xi.width = w->core.width;
  288.   
  289.   ms_calculate_job_parameters(&w->ms.xi, &w->ms.xi.job);
  290.  
  291. #ifdef LABEL
  292.   underflow=(w->ms.xi.job.delta.re == 0 || w->ms.xi.job.delta.im == 0);
  293.  
  294.   if(underflow && !w->ms.underflow)
  295.   { MsCreateUnderflowLabel(w);
  296.   }
  297.   if(!underflow && w->ms.underflow)
  298.   { XtDestroyWidget(w->ms.underflow_label);
  299.   }
  300.   w->ms.underflow = underflow;
  301. #endif
  302.  
  303.   /* if it had a rectangle buffer already, destroy it */
  304.   if(w->ms.rectbuffer)
  305.     XDestroyImage(w->ms.rectbuffer);
  306.  
  307.   /* create the rectangle buffer */
  308.   w->ms.rectbuffer=
  309.     XCreateImage(XtDisplay(w), DefaultVisualOfScreen(XtScreen(w)), 
  310.          DefaultDepthOfScreen(XtScreen(w)), ZPixmap, 0, (char *) NULL, 
  311.          w->ms.xi.chunk_width, w->ms.xi.chunk_height, 32,
  312.          0 /* zero means let XCreateImage determine bytes/line */
  313.         );
  314.   w->ms.rectbuffer_size=(unsigned) w->ms.rectbuffer->bytes_per_line * 
  315.     w->ms.xi.chunk_height;
  316.   w->ms.rectbuffer->data=(char *) XtMalloc(w->ms.rectbuffer_size);
  317.  
  318.   if(w->ms.xi.job.iteration_limit == 0) /* not set yet? */
  319.   { /* iterate as far as possible by default */
  320.     w->ms.xi.job.iteration_limit = MaxIterations(w->ms.mama);
  321.   }
  322.   else
  323.     if(w->ms.xi.job.iteration_limit > MaxIterations(w->ms.mama))
  324.     { w->ms.xi.job.iteration_limit=MaxIterations(w->ms.mama);
  325.       XtAppWarning(thisApp,
  326.            "Iteration limit truncated");
  327.     }
  328.  
  329.   w->ms.xi.bytes_per_count=(w->ms.xi.job.iteration_limit > 256 ? 2 : 1);
  330.  
  331.   /* determine the kind of draw routine to use depending on */
  332.   /* display characteristics and iteration count size */
  333.  
  334.   if(w->ms.rectbuffer->bits_per_pixel == 8)
  335.     w->ms.type=DISP_8plane;
  336.   else if(w->ms.rectbuffer->bits_per_pixel == 1  &&
  337.         w->ms.rectbuffer->bitmap_unit==32 &&
  338.         w->ms.rectbuffer->bitmap_bit_order != LSBFirst)
  339.       w->ms.type=DISP_1plane32msb;
  340.   else if(w->ms.rectbuffer->bits_per_pixel == 1  &&
  341.             w->ms.rectbuffer->bitmap_unit==32 &&
  342.             w->ms.rectbuffer->bitmap_bit_order == LSBFirst)
  343.       w->ms.type=DISP_1plane32lsb;
  344.   else
  345.   { w->ms.type=DISP_generic;
  346.     XtAppWarning(thisApp,
  347.          "No special case support for this display type;\n\
  348. drawing a pixel at a time, this will be very slow.");
  349.   }
  350.  
  351.   w->ms.type |= (w->ms.xi.bytes_per_count==2) ? ITER_WORD : ITER_BYTE;
  352.  
  353.   /* We now have a new configuration; give it a unique number */
  354.   w->ms.xi.configuration++;
  355. }
  356.  
  357.  
  358. /* Calculate the coordinates for the rubberband box given the initial */
  359. /* and current mouse position (box_origin, box_corner). Use the box_origin */
  360. /* as either the center or the oppsite corner depending on the center_box */
  361. /* flag */
  362.  
  363. struct box UnflipBox(w)
  364.      MsWidget w;
  365. { struct box r;
  366.   if(w->ms.center_box)
  367.   { int halfwidth=ABS(w->ms.box_corner.x - w->ms.box_origin.x);
  368.     int halfheight=ABS(w->ms.box_corner.y - w->ms.box_origin.y);
  369.     r.x0=w->ms.box_origin.x-halfwidth;
  370.     r.x1=w->ms.box_origin.x+halfwidth;
  371.     r.y0=w->ms.box_origin.y-halfheight;
  372.     r.y1=w->ms.box_origin.y+halfheight;
  373.   }
  374.   else
  375.   { r.x0=MIN(w->ms.box_origin.x, w->ms.box_corner.x);
  376.     r.x1=MAX(w->ms.box_origin.x, w->ms.box_corner.x);
  377.     r.y0=MIN(w->ms.box_origin.y, w->ms.box_corner.y);
  378.     r.y1=MAX(w->ms.box_origin.y, w->ms.box_corner.y);
  379.   }
  380.   return(r);
  381. }
  382.  
  383.  
  384. /* Zoom into the area selected using the box.  If "pop", pop up a new */
  385. /* window.  If "julia", show the Julia set corresponding to the point */
  386. /* at the center of the box.  If "outwards", zoom out instead of in. */
  387.  
  388. void ZoomIn(w, pop, julia, outwards)
  389.        MsWidget w;
  390.        int pop;
  391.        int julia;
  392.        int outwards;
  393. { struct box b;
  394.   double scale;
  395.   double new_xrange, new_center_x, new_center_y;
  396.   Arg arglist[16];
  397.   int num_args;
  398.   Arg shell_arglist[16];
  399.   int num_shell_args;
  400.   int boxwidth;
  401.   double nx, ny;
  402.  
  403.   if(!w->ms.box_exists)
  404.     return;
  405.  
  406.   b=UnflipBox(w);  
  407.  
  408.   boxwidth = b.x1-b.x0;
  409.  
  410.   /* caculate location of box center normalized so that 0 = window center, */
  411.   /* +-0.5 = window edge */
  412.   nx = ((((double) b.x0+b.x1)/2)-(w->core.width/2)) / (double)(w->core.width);
  413.   ny = ((((double) b.y0+b.y1)/2)-(w->core.height/2)) /    (double)(w->core.height);
  414.       
  415.   if(outwards) /* zoom out */
  416.   { if(boxwidth==0)
  417.     { /* avoid division by zero */
  418.       new_xrange = default_range;
  419.       new_center_x = w->ms.xi.center_x;
  420.       new_center_y = w->ms.xi.center_y;
  421.     }
  422.     else
  423.     { scale = (double) w->core.width / (double) boxwidth;
  424.       new_xrange = w->ms.xi.xrange * scale;
  425.       new_center_x = w->ms.xi.center_x - nx * scale * w->ms.xi.xrange;
  426.       new_center_y = w->ms.xi.center_y - ny * scale * w->ms.xi.yrange;
  427.     }
  428.   }
  429.   else /* zoom in */
  430.   { scale = (double) boxwidth / (double) (w->core.width);
  431.     new_xrange = w->ms.xi.xrange * scale;
  432.     new_center_x = w->ms.xi.center_x + nx * w->ms.xi.xrange;
  433.     new_center_y = w->ms.xi.center_y + ny * w->ms.xi.yrange;
  434.   }
  435.   
  436.   /* build arguments for the changed resources in the zoomed widget */
  437.   num_args=0;
  438.  
  439.   /* Transition from Mandelbrot to Julia set */
  440.   if(julia && !(w->ms.xi.julia))
  441.   { XtSetArg(arglist[num_args], XtNJulia, True); num_args++;
  442.     /* Set the C parameter (chooses a Julia set out of infinitely many) */
  443.     XtSetArg(arglist[num_args], XtNCX, &new_center_x); num_args++;
  444.     XtSetArg(arglist[num_args], XtNCY, &new_center_y); num_args++;
  445.     /* This is an initial Julia picture, so show the whole Julia set */
  446.     XtSetArg(arglist[num_args], XtNRange, &default_julia_range); num_args++;
  447.     XtSetArg(arglist[num_args], XtNCenterX,
  448.          &default_julia_center_x); num_args++;
  449.     XtSetArg(arglist[num_args], XtNCenterY,
  450.          &default_julia_center_y); num_args++;
  451.   }
  452.   else /* No change in M/J mode */
  453.   { XtSetArg(arglist[num_args], XtNJulia, w->ms.xi.julia); num_args++;
  454.     XtSetArg(arglist[num_args], XtNCenterX, &new_center_x); num_args++;
  455.     XtSetArg(arglist[num_args], XtNCenterY, &new_center_y); num_args++;
  456.     XtSetArg(arglist[num_args], XtNRange, &new_xrange); num_args++;
  457.     /* these two parameters are redundant in the Mandelbrot mode */
  458.     XtSetArg(arglist[num_args], XtNCX, &w->ms.xi.c_x); num_args++;
  459.     XtSetArg(arglist[num_args], XtNCY, &w->ms.xi.c_y); num_args++;
  460.   }
  461.  
  462.   XtSetArg(arglist[num_args], XtNMama, w->ms.mama); num_args++;
  463.  
  464.   if(pop)
  465.   { num_shell_args = 0;
  466.     /* make the new window as big as this one initially */
  467.     XtSetArg(shell_arglist[num_shell_args], XtNheight, w->core.height);
  468.     num_shell_args++;
  469.     XtSetArg(shell_arglist[num_shell_args], XtNwidth, w->core.width);
  470.     num_shell_args++;
  471.     /* create a new pop-up window for the zoomed area */
  472.     PopupAnother(w->ms.mama, shell_arglist, num_shell_args, arglist, num_args);
  473.   }
  474.   else 
  475.   {
  476. #if 1
  477.     /* zoom using the old window: just set the changed resources */
  478.     EraseBox(w);
  479.     XtSetValues(w, arglist, num_args);
  480. #else
  481.     /* Code under construction.  Hazardous area, do not enter. */
  482.     /* unmap the shell widget */
  483.     XtUnmapWidget(XtParent(w));
  484.     /* should make new window use same location as the old one, */
  485.     /* without WM intervention.  How? */
  486.     num_shell_args = 0;
  487.     /* make the new window as big as this one initially */
  488.     XtSetArg(shell_arglist[num_shell_args], XtNheight, w->core.height);
  489.     num_shell_args++;
  490.     XtSetArg(shell_arglist[num_shell_args], XtNwidth, w->core.width);
  491.     num_shell_args++;
  492.     /* create a new pop-up window for the zoomed area */
  493.     PopupAnother(w->ms.mama, shell_arglist, num_shell_args, arglist, num_args);
  494. #endif
  495.   }
  496. }
  497.  
  498.  
  499. /* Action routine interface to ZoomIn */
  500.  
  501. static void ZoomAction(w, event, params, nparams)
  502.      MsWidget w;
  503.      XEvent *event;
  504.      String *params;
  505.      Cardinal *nparams;
  506.   if(*nparams != 3)
  507.   { XtAppWarning(thisApp, "ZoomAction: wrong number of arguments");
  508.     return;
  509.   }
  510.   ZoomIn(w, params[0][0] == 'p', params[1][0] == 'j', params[2][0] == 'o');
  511. }
  512.  
  513.  
  514. /* Handle widget exposure */
  515. /* Can't call this "Expose" because that is #defined to 12 in X.h! */
  516.  
  517. /*ARGSUSED*/
  518. static void DoExpose (w, e, r)
  519.      MsWidget    w;
  520.      XEvent *e;
  521.      Region r;
  522. {
  523. #ifdef LABEL
  524.   /* It's no use redrawing if underflow has occured */
  525.   if(w->ms.underflow)
  526.     return;
  527. #endif
  528.  
  529.   /* remove the box for the duration of the update */
  530.   if(w->ms.xi.chunks_out==0)
  531.     HideBox(w);
  532.   
  533.   ms_dispatch_rect(&w->ms.xi, (char *) w,
  534.            e->xexpose.x, e->xexpose.y,
  535.            e->xexpose.width, e->xexpose.height
  536.           );
  537. }
  538.  
  539.  
  540. /* Draw (or undraw) the rubberband box */
  541.  
  542. static void InvertBox(w)
  543.      MsWidget w;
  544. { struct box b;
  545.   /* draw only if no update is in progress */
  546.   if(!w->ms.box_hidden)
  547.   { int armx, army;
  548.     armx=army=w->ms.crosshair_size;
  549.     b=UnflipBox(w);
  550.     XDrawRectangle(XtDisplay(w), XtWindow(w), w->ms.box_gc,
  551.            b.x0, b.y0, b.x1-b.x0, b.y1-b.y0);
  552.     if(armx || army)
  553.     { /* draw a crosshair at the center of the selected area */
  554.       int xc = (b.x0+b.x1)/2;
  555.       int yc = (b.y0+b.y1)/2;
  556.       XDrawLine(XtDisplay(w), XtWindow(w), w->ms.box_gc,
  557.         xc-armx, yc, xc+armx, yc);
  558.       XDrawLine(XtDisplay(w), XtWindow(w), w->ms.box_gc,
  559.         xc, yc-army, xc, yc+army);
  560.     }
  561.     w->ms.box_exists = !(w->ms.box_exists);
  562.   }
  563. }
  564.  
  565.  
  566. /* Erase the rubberband box if it exists */
  567.  
  568. static void EraseBox(w)
  569.      MsWidget w;
  570. { if(w->ms.box_exists) InvertBox(w);
  571. }
  572.  
  573.  
  574.  
  575. /* Create the rubberband box */
  576.  
  577. static void BeginBoxAction(w, event, params, nparams)
  578.      MsWidget w;
  579.      XEvent *event;
  580.      String *params;
  581.      Cardinal *nparams;
  582. { EraseBox(w);
  583.   w->ms.box_origin.x=w->ms.box_corner.x=((XButtonEvent *) event)->x;
  584.   w->ms.box_origin.y=w->ms.box_corner.y=((XButtonEvent *) event)->y;
  585.   InvertBox(w);
  586. }
  587.  
  588.  
  589. /* Stretch the rubberband box */
  590.  
  591. static void StretchBoxAction(w, event, params, nparams)
  592.      MsWidget w;
  593.      XEvent *event;
  594.      String *params;
  595.      Cardinal *nparams;
  596. { EraseBox(w);
  597.   w->ms.box_corner.x=((XButtonEvent *) event)->x;
  598.   w->ms.box_corner.y=((XButtonEvent *) event)->y;
  599.   InvertBox(w);
  600. }
  601.  
  602.  
  603. /* Stop stretching the rubberband box (currently a no-op) */
  604.  
  605. static void EndBoxAction(w, event, params, nparams)
  606.      MsWidget w;
  607.      XEvent *event;
  608.      String *params;
  609.      Cardinal *nparams;
  610. {
  611. }
  612.  
  613.  
  614. /* Hide the box when beginning an asynchronous update */
  615.  
  616. static void HideBox(w)
  617.      MsWidget w;
  618. { if(w->ms.box_hidden==0 && w->ms.box_exists)
  619.     InvertBox(w);
  620.   w->ms.box_hidden++;
  621. }
  622.  
  623.  
  624. /* Unhide the box when an asynchronous update is done */
  625.  
  626. static void UnhideBox(w)
  627.      MsWidget w;
  628. { w->ms.box_hidden--;
  629.   if(w->ms.box_hidden==0 && w->ms.box_exists) 
  630.     InvertBox(w);
  631. }
  632.  
  633.  
  634. /* Realize the widget */
  635.  
  636. static void
  637. Realize (w, valueMask, attrs)
  638.      MsWidget w;
  639.      XtValueMask *valueMask;
  640.      XSetWindowAttributes *attrs;
  641. { /* setting the colormap here is probably redundant */
  642.   attrs->backing_store=Always;
  643.   attrs->save_under=False;
  644.   attrs->bit_gravity=ForgetGravity;
  645.   attrs->cursor=w->ms.my_cursor;
  646.   attrs->colormap=MamaColormap(w->ms.mama);
  647.   XtCreateWindow (w, InputOutput, (Visual *) CopyFromParent,
  648.     *valueMask | CWBackingStore | CWSaveUnder| CWBitGravity | CWCursor |
  649.           CWColormap, attrs);
  650.   MsPrecalculate(w);
  651. #ifdef MENU
  652.   MsCreateMenu(w, !w->ms.xi.julia);
  653. #endif
  654. }
  655.  
  656.  
  657. /* Destroy the widget */
  658.  
  659. static void
  660. Destroy (w)
  661.      MsWidget w;
  662. { XtReleaseGC(w, w->ms.box_gc);
  663.   XtFree((char *) w->ms.rectbuffer);
  664. }
  665.  
  666.  
  667. /* Update widget resources */
  668.  
  669. static Boolean SetValues(current, request, new)
  670.      MsWidget current, request, new;
  671. { MsPrecalculate(new); /* do the dirty work */
  672.   return(True); /* widget must be redisplayed */
  673. }
  674.  
  675.  
  676. /* Resize the widget */
  677.  
  678. static void
  679. Resize(w)
  680.      MsWidget w;
  681. { MsPrecalculate(w); /* do the dirty work */
  682. }
  683.  
  684.  
  685. /* Print the view coordinates */
  686.  
  687. void WindowStats(w)
  688.      MsWidget w;
  689. { (void) printf("current picture area: x = %f .. %f, y = %f .. %f\n",
  690.         w->ms.xi.center_x - w->ms.xi.xrange / 2,
  691.         w->ms.xi.center_x + w->ms.xi.xrange / 2,
  692.         w->ms.xi.center_y - w->ms.xi.yrange / 2,
  693.         w->ms.xi.center_y + w->ms.xi.yrange / 2
  694.            );
  695.   (void) printf("return here with: xms ");
  696.   if(w->ms.xi.julia)
  697.     (void) printf("-julia -cx %f -cy %f ", w->ms.xi.c_x, w->ms.xi.c_y);
  698.   (void) printf("-x %f -y %f -range %f\n",
  699.            w->ms.xi.center_x, w->ms.xi.center_y, w->ms.xi.xrange);
  700. }
  701.  
  702.  
  703. /* Action routine for the above */
  704.  
  705. static void WindowStatsAction(w, event, params, nparams)
  706.      MsWidget w;
  707.      XEvent *event;
  708.      String *params;
  709.      Cardinal *nparams;
  710. { WindowStats(w);
  711. }
  712.  
  713.  
  714. /* Print slave performance statistics */
  715.  
  716. static void ApplStatsAction(w, event, params, nparams)
  717.      MsWidget w;
  718.      XEvent *event;
  719.      String *params;
  720.      Cardinal *nparams;
  721. { SlaveStatistics(w->ms.mama);
  722. }
  723.  
  724.  
  725. /* auxiliary macro for ms_draw: */
  726.  
  727. #define DRAW_SINGLEPLANE(iter_type, init_mask, shift_op) \
  728.  { iter_type *datap = (iter_type *) data; \
  729.    for(j=0; j<height; j++) \
  730.    { unsigned char *bufp = (unsigned char *) w->ms.rectbuffer->data + \
  731.        (w->ms.rectbuffer->bytes_per_line * j); \
  732.      for(i=0; i<width; ) /* for each byte */ \
  733.      { unsigned pixbyte = 0; \
  734.        unsigned mask = init_mask; \
  735.        unsigned end=MIN(width, i+8); \
  736.        for(; i<end; i++) /* for each bit in the byte */ \
  737.        { if(pixels[*datap++]) \
  738.        pixbyte |= mask; \
  739.      mask shift_op 1; \
  740.        } \
  741.        *bufp++ = pixbyte; \
  742.      } \
  743.    } \
  744.  }
  745.  
  746.  
  747. /* This function is called when a chunk has been completed by a slave */
  748. /* to draw it on the screen */
  749.  
  750. void ms_draw(client, client_data, data)
  751.      char *client;
  752.      char *client_data;
  753.      char *data; 
  754. { MsWidget w = (MsWidget) client;
  755.   register int i, j;
  756.   unsigned int x, y, width, height;
  757.  
  758.   ms_client_info *the_info = (ms_client_info *) client_data;
  759.  
  760.   unsigned long *pixels = MamaPixels(w->ms.mama);
  761.  
  762.   /* Ignore the reply if the widget has changed shape or something */
  763.   if(the_info->configuration == w->ms.xi.configuration)
  764.   { x=the_info->s.x; 
  765.     y=the_info->s.y; 
  766.     width=the_info->s.width;
  767.     height=the_info->s.height;
  768.  
  769.     /* 16-bit iteration counts from the slave need to be */
  770.     /* converted from network byte order.  It is faster */
  771.     /* to do it all at once here than to call ntohs() */
  772.     /* in the tight loops below.  Any decent compiler will */
  773.     /* optimize away the whole "if" statement if the CPU */
  774.     /* is big-endian; if it is little-endian then a single */
  775.     /* redundant ntohs() call will remain in the "if" condition. */
  776.  
  777.     if(ntohs(1) != 1)
  778.     { if(w->ms.xi.bytes_per_count == sizeof(unsigned short))
  779.       {    unsigned short *end;
  780.     register unsigned char *p;
  781.     end = (unsigned short *) data + (width * height);
  782.     for(p = (unsigned char *) data; p < (unsigned char *) end; p += 2)
  783.     { unsigned char tmp;
  784.       tmp = *p;
  785.       *p = *(p+1);
  786.       *(p+1) = tmp;
  787.     }
  788.       }
  789.     }
  790.  
  791.     /* sorry about the combinatorial explosion, but this part easily */
  792.     /* becomes a bottleneck if all the tests are done inside the loop */
  793.     switch(w->ms.type)
  794.     {
  795.     case ITER_BYTE|DISP_1plane32msb:
  796.       DRAW_SINGLEPLANE(unsigned char, 0x80, >>=);
  797.       break;
  798.     case ITER_WORD|DISP_1plane32msb:
  799.       DRAW_SINGLEPLANE(unsigned short, 0x80, >>=);
  800.       break;
  801.     case ITER_BYTE|DISP_1plane32lsb:
  802.       DRAW_SINGLEPLANE(unsigned char, 0x01, <<=);
  803.       break;
  804.     case ITER_WORD|DISP_1plane32lsb:
  805.       DRAW_SINGLEPLANE(unsigned short, 0x01, <<=);
  806.       break;
  807.     case ITER_BYTE|DISP_8plane:
  808.       /* Quick-and-dirty drawing of 8-bit values on 8-plane displays */
  809.       { unsigned char *datap = (unsigned char *) data;
  810.     for(j=0; j<height; j++)
  811.     { unsigned char *bufp= (unsigned char *)
  812.         w->ms.rectbuffer->data + (w->ms.rectbuffer->bytes_per_line * j);
  813.       for(i=0; i<width; i++)
  814.       { *bufp++ = pixels[*datap++];
  815.       }
  816.     }
  817.       }
  818.       break;
  819.     case ITER_WORD|DISP_8plane:
  820.       /* Quick-and-dirty drawing of 16-bit values on 8-plane displays */
  821.       { unsigned short *datap = (unsigned short *) data;
  822.     for(j=0; j<height; j++)
  823.     { unsigned char *bufp= (unsigned char *)
  824.         w->ms.rectbuffer->data + (w->ms.rectbuffer->bytes_per_line * j);
  825.       for(i=0; i<width; i++)
  826.       { *bufp++ = pixels[*datap++];
  827.       }
  828.     }
  829.       }
  830.       break;
  831.     case ITER_BYTE|DISP_generic:
  832.       /* Slow but portable drawing of 8-bit values on 8-plane displays */
  833.       { unsigned char *datap = (unsigned char *) data;
  834.     for(j=0; j<height; j++)
  835.     { for(i=0; i<width; i++)
  836.         XPutPixel(w->ms.rectbuffer, i, j, pixels[*datap++]);
  837.     }
  838.       }
  839.       break;
  840.     case ITER_WORD|DISP_generic:
  841.       /* Slow but portable drawing of 16-bit values on 8-plane displays */
  842.       { unsigned short *datap = (unsigned short *) data;
  843.     for(j=0; j<height; j++)
  844.     { for(i=0; i<width; i++)
  845.         XPutPixel(w->ms.rectbuffer, i, j, pixels[*datap++]);
  846.     }
  847.       }
  848.       break;
  849.     default:
  850.       XtAppError(thisApp, "no drawing routine defined for this display type");
  851.     }
  852.  
  853.     if(w->ms.sony_bug_workaround)
  854.     { /* ugly workaround for a bug causing some Sony X servers to */
  855.       /* crash in greyscale mode */
  856.       height=32;
  857.       width=32;
  858.     }
  859.  
  860.     /* go do it! */
  861.     XPutImage(XtDisplay(w), XtWindow(w), DefaultGCOfScreen(XtScreen(w)),
  862.           w->ms.rectbuffer, 
  863.           0, 0, /* position in the buffer */
  864.           x, y, /* position on the screen */
  865.           width, height);
  866.   }
  867.   w->ms.xi.chunks_out--; /* one less to go */
  868.  
  869.   if(w->ms.xi.chunks_out==0)
  870.     UnhideBox(w);
  871. }
  872.  
  873.  
  874. /* Destroy this window (only) */
  875.  
  876. static void
  877. CloseAction(w, event, params, nparams)
  878.      MsWidget w;
  879.      XEvent *event;
  880.      String *params;
  881.      Cardinal *nparams;
  882. { XtDestroyWidget(XtParent(w)); /* destroy the shell widget */
  883. }
  884.  
  885.  
  886. /* Ask Mama to shut down */
  887.  
  888. static void 
  889. QuitAction(w, event, params, nparams)
  890.      MsWidget w;
  891.      XEvent *event;
  892.      String *params;
  893.      Cardinal *nparams;
  894. { Shutdown(w->ms.mama);
  895. }
  896.